Using the Drag Manager to Interact with and Manipulate File System EntitiesBy Pete Gontier |
CONTENTS
Introducing |
The Drag Manager defines two data flavors for interacting with and manipulating file system entities. While The Drag Manager Programmer's Guide explains these flavors, it does not provide sufficient detail for a complete understanding of how to use them. Developers who are interested in "teaching" (or even those who have already taught) their applications to interact with and manipulate file system entities via the Drag Manager should read this Technote. This Technote assumes you are familiar with the material
in the Drag Manager Programmer's Guide and that, in
particular, you have read pages 2-36 and 2-37 and understand
the operation of a You can download a complete version of the code snippets in this Technote, FinderDragPro Metrowerks Project, as well as the Drag Manager Programmer's Guide, by clicking on the item here or by clicking on the appropriate icon in the Downloadables section at the end of this Note. |
Introducing
|
Note:
|
Important:
|
Using
|
struct HFSFlavor { OSType fileType; // file type OSType fileCreator; // file creator unsigned short fdFlags; // Finder flags FSSpec fileSpec; // file system specification }; typedef struct HFSFlavor HFSFlavor; |
Sending flavorTypeHFSTo originate a drag containing The next step is to initialize the Table 1. The
These values are a hint to potential drag receivers that they are dealing with something other than a file. They are the same as the ones you would use in your application's bundle resource to let Finder know your app will accept folders and disks dropped onto your application's icon. Snippet #1: Deciding how to set the
|
Coping with Finder BugsDragging From Finder's perspective, there are two cases for
receiving
Finder is AppleEvent-intensive. It sends itself
AppleEvents to order itself to do all sorts of things,
including displaying the progress window for copying files.
However, Finder's drag-receiving code mistakenly sends these
particular AppleEvents to the front process instead of the
current process. The front process is generally the
application which originated the drag. Since the application
does not have handlers for these events, AppleEvent Manager
returns an error to Finder's Until this bug is fixed, your application can work around the problem by "handling" these AppleEvents. On systems under which Finder has been fixed, the handler will simply lie dormant in your app, because the AppleEvents will be sent to Finder, not your app. Unfortunately, it doesn't do any good to "reflect" these events back to the Finder; trust us, we've tried. This means you'll have to do without the progress dialog, but this is better than abject failure. Snippet #2: Receiving bogus AppleEvents from Finder
|
Receiving
|
static pascal Size MinimumBytesForFSSpec (const FSSpec *fss) { // callers can and do assume this does not move memory return sizeof (*fss) - sizeof (fss->name) + *(fss->name) + 1; } |
Snippet #4: Extracting flavorTypeHFS
data
pascal OSErr GetHFSFlavorFromDragReference (DragReference dragRef, ItemReference itemRef, HFSFlavor *hfsFlavor) { OSErr err = noErr; Size size = sizeof (*hfsFlavor); err = GetFlavorData (dragRef,itemRef,flavorTypeHFS,hfsFlavor,&size,0); if (!err) { Size minSize = sizeof (*hfsFlavor) - sizeof (hfsFlavor->fileSpec); minSize += MinimumBytesForFSSpec (&(hfsFlavor->fileSpec)); // see snippet 3 for MinimumBytesForFSSpec if (size < minSize) err = cantGetFlavorErr; } return err; } |
Using
|
struct PromiseHFSFlavor { OSType fileType; // file type OSType fileCreator; // file creator unsigned short fdFlags; // Finder flags FlavorType promisedFlavor; // promised flavor }; typedef struct PromiseHFSFlavor PromiseHFSFlavor; |
Sending
|
pascal OSErr AddDragItemFlavorTypePromiseHFS (DragReference dragRef, ItemReference itemRef, OSType fileType, OSType fileCreator, UInt16 fdFlags, FlavorType promisedFlavor) { OSErr err = noErr; PromiseHFSFlavor phfs; phfs.fileType = fileType; phfs.fileCreator = fileCreator; phfs.fdFlags = fdFlags; phfs.promisedFlavor = promisedFlavor; if (!(err = AddDragItemFlavor (dragRef,itemRef,flavorTypePromiseHFS, &phfs,sizeof(phfs),flavorNotSaved))) { err = AddDragItemFlavor (dragRef,itemRef,promisedFlavor,nil,0,flavorNotSaved); } return err; } |
|
|
Add any other flavors you might want to
provide in this DragReference
, and you're ready
to call TrackDrag
.
When Drag Manager requests a FlavorType
equal to the
promisedFlavor
field of your flavorTypePromiseHFS
data, it's
your cue to keep your promise by delivering the
file. Keeping the promise involves finding out where the
drag receiver wants the file to end up, deciding where to
create the file, and creating the file. You'll do this in
your DragSendDataProc
associated with the DragReference
.
First, your DragSendDataProc
will need to find out where
the drag receiver wants the file. You'll need to call
GetDropLocation
, which will produce an AEDesc
record. The type of the data found in this record is defined
by the drag receiver. Finder, for example, provides typeAlias
data. To convert this data to an
FSSpec
, coerce its type to typeFSS
and copy the FSSpec
data
out of the resulting descriptor.
Snippet #6: Extracting the drop folder
pascal OSErr GetDropDirectory (DragReference dragRef, FSSpecPtr fssOut) { OSErr err = noErr; AEDesc dropLocAlias = { typeNull, nil }; if (!(err = GetDropLocation (dragRef,&dropLocAlias))) { if (dropLocAlias.descriptorType != typeAlias) err = paramErr; else { AEDesc dropLocFSS = { typeNull, nil }; if (!(err = AECoerceDesc (&dropLocAlias,typeFSS,&dropLocFSS))) { // assume MinimumBytesForFSSpec does not move memory FSSpecPtr fss = (FSSpecPtr) *(dropLocFSS.dataHandle); BlockMoveData (fss,fssOut,MinimumBytesForFSSpec(fss)); // see snippet 3 for MinimumBytesForFSSpec err = AEDisposeDesc (&dropLocFSS); } } if (dropLocAlias.dataHandle) { OSErr err2 = AEDisposeDesc (&dropLocAlias); if (!err) err = err2; } } return err; } |
Note
|
If the drop location data is not of typeAlias
, the call to
AECoerceDesc
will fail.
Your DragSendDataProc
will probably want to provide no data
and return an error in this situation. However, be aware
that applications other than Finder are free to provide a
drop location of typeAlias
(and some even do), so don't rely
on typeAlias
signifying that Finder is the drop receiver.
Note
|
Note
|
Creating the FileOnce you've decided where to put the file, you can create it by calling a function like this one: Snippet #7: Creating the promised file or folder
|
Deferring Writing the FileOnce the file is created, you may or may not want to
write its contents in your In this situation, you'll want to open the file in your
Finishing the DragOnce (and only if) the file has been successfully
created, you should let the drag receiver know what the
filename was and where the file was created. To do this,
call Snippet #10: Adding the promised
Impersonating Find FileIf you need to provide a
The section Coping with Find File elsewhere in this Note details why these steps are necessary. The following snippet implements a decision tree which tells its caller whether to copy a file the caller is dropping: Snippet #11: Deciding whether to copy a dropped file
|
SummaryThere are two file system-oriented flavor types
associated with the Drag Manager. One,
Here are some important lessons worth repeating:
|
|
|
The following SmartFriends™ provided essential research assistance and technical review in support of this Technote: Andy Bachorski, Brian Bechtel, Steve Christensen, Steve Dorner, Dave Evans, Nitin Ganatra, Peter Lewis, Bill Monk, Matt Mora, Pete Resnick, Leonard Rosenthol, Rich Siegel, jud spencer, James Thomson.
AppendicesThe Appendices to this Technote contain code snippets which are necessary for a full understanding of other snippets in the Technote but would have obstructed the flow of the main text stream. Appendix AThis is a utility function called by the functions in
Appendices B and C. It allocates and populates a
Appendix BThese functions are intended to follow the same API as
Appendix CThis function returns the directory ID of a given folder.
It calls
|
Technotes
Previous Technote |
Contents |
Next Technote